package com.yms.string;


/**
 * @version : 1.0
 * @author: yangmingsong
 * @date: 2022/7/9-07-09-13:57
 * @description: spring5Test 从内存来看字符串的存储，以及构建
 */
public class TestStringResourceDeferent {

    public static void main(String[] args) {
        //1、测试String s = "123"相同的字符串是否内存地址相同
        String s = "123";//debug得到 s的value值是char[3]@536
        String s1 = "123";//下方也得到的是char[3]@536
        System.out.println(s == s1); // 所以得知这两个变量s和s1在内存中是相同的 true
        //已知通过这种方式创建的字符串在处于字符串常量池中，所以我们可以得知当字符串常量池中存在我们需要创建的字符串时就不会另外创建，而是直接引用
        //所以我们可以得知，字符串常量池中保存的值是唯一的

        //2、通过字符串的拼接了解字符串常量池中纵使没有对象指向，但只要是之前不存在的字符串，就会被创建
        s = s + "456";//从char[3]@536变成了char[6]@538  经过jclasslib分析常量池中信息得知456这个字符串已经存在
        String intern = s.intern(); //char[6]@538
        System.out.println(s == intern); // true
        //所以通过("789")这种方式会再次在字符串常量池中创建字符串对象，虽然没有变量指向，但仍然会存在
        //通过new StringBuilder() 或者 new StringBuffer() 方式创建的字符串，以及拼接上的内存细节
        String x = "789"; //char[3]@540 这是字符串常量池的地址
        StringBuilder stringBuilder = new StringBuilder(x); //StringBuilder@541 而里面的value 是这个对象具有的一个成员变量char[] value 地址为：char[19]@543
        //再分析"789"这个字符串是否会在字符串常量池中被创建----》经过jclasslib分析"789"这个字符串的确会被创建
        StringBuffer stringBuffer = new StringBuffer(x);
        String s3 = stringBuffer.toString();
        String s2 = stringBuilder.toString();//toString()方法会重新new一个String对象 因此char[3]@546这个地址是堆空间的地址
        String intern1 = s2.intern();
        //3、前面分析789已经在字符串常量池中存在根据intern()方法，其实是去字符串常量池中找到这个字符串的值，将其转为字符串常量池中的地址，
        //所以char[3]@540这个是字符串常量池的信息
        System.out.println(s2 == intern1); // false
        System.out.println(intern1 == x); //true
        //4、用下列方式再次证明字符串显示表明new StringBuilder("789")是否会存在于字符串常量池中
        char[] chars = {'a','b','c'}; // char[3]@549
        String a = new String(chars, 0, 3);// char[3]@553 经过jclasslib分析，"abc"并不存在于字符串常量池中
        String intern2 = a.intern();//jdk1.8中内存地址也是char[3]@553，表明如果字符串常量池中没有这个字符串，并不会在字符串常量池中创建
        System.out.println(a == intern2); // true

    }
}
